﻿#include "SDL_Canvas.h"

SDL_CCanvas::SDL_CCanvas() :
	m_pMainSurface(NULL)
{
	m_rMainArea.Set(0, 0, 0, 0);
}

SDL_CCanvas::~SDL_CCanvas()
{
	SDL_Surface* _pSurface = NULL;

	SDLBuffer::iterator _it = m_mapBuffer.begin();
	while(_it != m_mapBuffer.end())
	{
		_pSurface = _it->second;
		m_mapBuffer.erase(_it);
		SDL_FREE_SURFACE(_pSurface);

		_it = m_mapBuffer.begin();
	}
}

bool SDL_CCanvas::OnInit(GAF_DWindowHandle hWindow)
{
	GAF_CHECK_R(hWindow != NULL, false);
	m_pMainSurface = (SDL_Surface*)hWindow;
	m_rMainArea.Set(0, 0, m_pMainSurface->w, m_pMainSurface->h);
	return true;
}

bool SDL_CCanvas::OnRender()
{
	ClearScreen();

	static GAF_CGraphics* s_pGraphics;

	FOREACH(GAF_CGraphics*, ppGraphics, m_lnkGraphicses)
	{
		s_pGraphics = *ppGraphics;

		if(s_pGraphics->GetScreenVisible())
		{
			if(s_pGraphics->OnPreRender(s_pGraphics))
			{
				switch(s_pGraphics->GetGType())
				{
				case GAF_GRAPHICS_IMAGE:
					if(((GAF_CImage*)s_pGraphics)->GetImageHandle(true) == NULL)
						break;

					RenderImage(
						&(s_pGraphics->Information()),
						((GAF_CImage*)s_pGraphics)->GetImageHandle(true),
						((GAF_CImage*)s_pGraphics)->GetImageInfo().bdlOther.GetInteger("PixelBit"),
						((GAF_CImage*)s_pGraphics)->GetClip(),
						s_pGraphics->GetScreenPosX(),
						s_pGraphics->GetScreenPosY(),
						s_pGraphics->GetAnchor(),
						s_pGraphics->GetAnchorOffset(),
						s_pGraphics->GetScreenAlpha(),
						s_pGraphics->GetScreenAngle(),
						s_pGraphics->GetScreenZoomX(),
						s_pGraphics->GetScreenZoomY(),
						s_pGraphics->GetScreenThrough(),
						GAF_RECT_NULL
						);
					break;
				case GAF_GRAPHICS_LABEL:
					RenderText(
						&(s_pGraphics->Information()),
						((GAF_CLable*)s_pGraphics)->GetText(),
						((GAF_CLable*)s_pGraphics)->GetFontFile(),
						((GAF_CLable*)s_pGraphics)->GetFontSize(),
						((GAF_CLable*)s_pGraphics)->GetStyle(),
						((GAF_CLable*)s_pGraphics)->GetFrontColour(),
						((GAF_CLable*)s_pGraphics)->GetBackColour(),
						s_pGraphics->GetScreenPosX(),
						s_pGraphics->GetScreenPosY(),
						s_pGraphics->GetAnchor(),
						s_pGraphics->GetAnchorOffset(),
						s_pGraphics->GetScreenAlpha(),
						s_pGraphics->GetScreenAngle(),
						s_pGraphics->GetScreenZoom(),
						s_pGraphics->GetScreenThrough(),
						GAF_RECT_NULL
						);
					break;
				case GAF_GRAPHICS_EFFECT:
					RenderImage(
						&(s_pGraphics->Information()),
						((GAF_CEffect*)s_pGraphics)->GetFrameImageHandle(),
						0,
						((GAF_CEffect*)s_pGraphics)->GetClip(),
						s_pGraphics->GetScreenPosX(),
						s_pGraphics->GetScreenPosY(),
						s_pGraphics->GetAnchor(),
						s_pGraphics->GetAnchorOffset(),
						s_pGraphics->GetScreenAlpha(),
						s_pGraphics->GetScreenAngle(),
						s_pGraphics->GetScreenZoomX(),
						s_pGraphics->GetScreenZoomY(),
						s_pGraphics->GetScreenThrough(),
						GAF_RECT_NULL
						);
					break;
				case GAF_GRAPHICS_FACE:
					break;
				case GAF_GRAPHICS_OTHER:
					s_pGraphics->OnRender();
					break;
				}
			}
		}
	}

	return true;
}

void SDL_CCanvas::AddGraphics(GAF_CGraphics* pGraphics)
{
	m_lnkGraphicses.Add(pGraphics);
}

void SDL_CCanvas::CleanGarphicses()
{
	m_lnkGraphicses.Clean();
}



bool SDL_CCanvas::RenderImage(
	GAF_CBundle* pInformation,	// 信息
	GAF_DImageHandle hImage,	// 图像指针
	SDL_DPixelBit pb,		// 图像像素位数
	GAF_SRect rClip,		// 图像剪裁区
	int nPosX, int nPosY,		// 绘制坐标
	GAF_DAnchor aAnchor,		// 锚点
	GAF_SPoint atAnchorOffset,	// 锚点偏移
	BYTE bAlpha,			// 透明度
	double dAngle,			// 旋转
	double dZoomX,			// X轴缩放
	double dZoomY,			// Y轴缩放
	GAF_EThroughType through,	// 穿屏模式
	GAF_SRect rCanvasArea		// 目标绘制区域
	)
{
	static SDL_Surface* s_pSurface;
	static SDL_Surface* s_pTransform;
	static GAF_SRect s_rImageClip;
	static bool s_isReturn;

	s_isReturn = true;

	if(hImage == NULL)
		return true;

	// 转换Surface资源
	s_pSurface = (SDL_Surface*)hImage;

	// 缩放 与 旋转
	s_pTransform = NULL;
	if(dAngle != GAF_ANGLE_DEFAULT || dZoomX != GAF_ZOOM_DEFAULT || dZoomY != GAF_ZOOM_DEFAULT)
	{
		char s_szBufferName[100];
		_MEMSET(s_szBufferName, 0, sizeof(s_szBufferName));
		_SPRINTF(s_szBufferName, "%d_%f_%f_%f", (int)s_pSurface, dAngle, dZoomX, dZoomY);

		s_pTransform = m_mapBuffer[s_szBufferName];

		if(s_pTransform == NULL)
		{
			// 缩放
			s_pTransform = rotozoomSurfaceXY(s_pSurface, dAngle, dZoomX, dZoomY, 0);
			if(s_pTransform != NULL)
			{
				// 加入缓冲
				m_mapBuffer[s_szBufferName] = s_pTransform;
			}
		}

		if(s_pTransform != NULL)
		{
			// 设置绘制对象
			s_pSurface = s_pTransform;
		}
	}

	// 计算尺寸
	if(rClip == GAF_RECT_NULL)
	{
		rClip.nWidth = s_pSurface->w;
		rClip.nHeight = s_pSurface->h;
	}
	s_rImageClip.nWidth = rClip.nWidth;
	s_rImageClip.nHeight = rClip.nHeight;

	// 计算坐标
	s_rImageClip.nX = nPosX + atAnchorOffset.nX;
	if((aAnchor & GAF_ANCHOR_HMASK) == GAF_ANCHOR_LEFT) {}
	else if((aAnchor & GAF_ANCHOR_HMASK) == GAF_ANCHOR_HCENTER)
		s_rImageClip.nX -= s_rImageClip.nWidth >> 1;
	else if((aAnchor & GAF_ANCHOR_HMASK) == GAF_ANCHOR_RIGHT)
		s_rImageClip.nX -= s_rImageClip.nWidth;

	s_rImageClip.nY = nPosY + atAnchorOffset.nY;
	if((aAnchor & GAF_ANCHOR_VMASK) == GAF_ANCHOR_TOP) {}
	else if((aAnchor & GAF_ANCHOR_VMASK) == GAF_ANCHOR_VCENTER)
		s_rImageClip.nY -= s_rImageClip.nHeight >> 1;
	else if((aAnchor & GAF_ANCHOR_VMASK) == GAF_ANCHOR_BUTTON)
		s_rImageClip.nY -= s_rImageClip.nHeight;

	// 计算位置
	if(through != GAF_THROUGH_NONE)
	{
		s_rImageClip.nX = s_rImageClip.nX % m_pMainSurface->w;
		if(s_rImageClip.nX < 0) s_rImageClip.nX += m_pMainSurface->w;
		s_rImageClip.nY = s_rImageClip.nY % m_pMainSurface->h;
		if(s_rImageClip.nY < 0) s_rImageClip.nY += m_pMainSurface->h;
	}
	else
	{
		if(s_rImageClip.Right() <= 0 || s_rImageClip.Left() >= m_pMainSurface->w ||
			s_rImageClip.Button() <= 0 || s_rImageClip.Top() >= m_pMainSurface->h)
		{
			s_isReturn = true;
			goto SDL_GOTO_SDLCANVPLAYER_RENDERIMAGE_RETURN;
		}
	}

	// 特殊混合与绘制
	s_isReturn &= RenderSurface(s_pSurface, s_rImageClip.nX, s_rImageClip.nY, rClip, pb, bAlpha);

	if(through != GAF_THROUGH_NONE)
	{ // 暂时不考虑绘制大于屏幕尺寸的图像穿越屏幕时的遮挡问题
		// 垂直穿越
		if(through == GAF_THROUGH_HORIZONTAL || through == GAF_THROUGH_BOTH)
		{
			if(s_rImageClip.Right() > m_pMainSurface->w)
			{
				s_isReturn &= RenderSurface(s_pSurface, s_rImageClip.nX - m_pMainSurface->w, s_rImageClip.nY, rClip, pb, bAlpha);
			}
		}

		// 水平穿越
		if(through == GAF_THROUGH_VERTICAL || through == GAF_THROUGH_BOTH)
		{
			if(s_rImageClip.Button() > m_pMainSurface->h)
			{
				s_isReturn &= RenderSurface(s_pSurface, s_rImageClip.nX, s_rImageClip.nY - m_pMainSurface->h, rClip, pb, bAlpha);
			}
		}

		// 都穿越
		if(through == GAF_THROUGH_BOTH)
		{
			if(s_rImageClip.Right() > m_pMainSurface->w && s_rImageClip.Button() > m_pMainSurface->h)
			{
				s_isReturn &= RenderSurface(s_pSurface, s_rImageClip.nX - m_pMainSurface->w, s_rImageClip.nY - m_pMainSurface->h, rClip, pb, bAlpha);
			}
		}
	}

SDL_GOTO_SDLCANVPLAYER_RENDERIMAGE_RETURN:

	return s_isReturn;
}

bool SDL_CCanvas::RenderText(
	GAF_CBundle* pInformation,	// 信息
	_STRING strText,		// 文字
	_STRING strFontFile,		// 字体文件
	int nFontSize,			// 文字尺寸
	GAF_SLableStyle* pStyle,	// 文字样式（优先）
	GAF_SColour cFront,		// 文字颜色
	GAF_SColour cBack,		// 背景颜色
	int nPosX, int nPosY,		// 绘制坐标
	GAF_DAnchor aAnchor,		// 锚点
	GAF_SPoint atAnchorOffset,	// 锚点偏移
	BYTE bAlpha,			// 透明度
	double dAngle,			// 旋转
	double dZoom,			// 缩放
	GAF_EThroughType through,	// 穿屏模式
	GAF_SRect rCanvasArea		// 目标绘制区域
	)
{
	// 加载字体
	TTF_Font* _pTTF = NULL;

	char _szFontMark[100];
	_SPRINTF(_szFontMark, "%s_%d", strFontFile.c_str(), nFontSize);

	_pTTF = m_tabFonts.Get(_szFontMark);

	if(_pTTF == NULL)
	{
		_pTTF = TTF_OpenFont(strFontFile.c_str(), nFontSize);
		if(_pTTF == NULL)
		{
			GAF_ERRMARK();
			return false;
		}
		m_tabFonts.Put(_szFontMark, _pTTF);
	}

	// 创建文字
	SDL_Surface* _pTextImage = NULL;
	if(pStyle == NULL)
	{ // 单色文字
		_pTextImage = CreateText(_pTTF, strText.c_str(), cFront);
	}
	else
	{ // 样式文字
		_pTextImage = CreateStyleText(_pTTF, strText, pStyle);
	}

	if(_pTextImage == NULL)
	{
		GAF_ERRMARK();
		return false;
	}

	// 绘制
	RenderImage(pInformation, _pTextImage, _pTextImage->format->BitsPerPixel, GAF_RECT_NULL,
		nPosX, nPosY, aAnchor, atAnchorOffset, bAlpha, dAngle, dZoom, dZoom, through, rCanvasArea);

	SDL_FREE_SURFACE(_pTextImage);

	return true;
}

bool SDL_CCanvas::RenderSurface(SDL_Surface* pSrcSurface,
	int nX, int nY, GAF_SRect rSrcClip, SDL_DPixelBit pb, BYTE bAlpha)
{
	if(rSrcClip == GAF_RECT_NULL)
	{
		rSrcClip.nX = 0;
		rSrcClip.nY = 0;
		rSrcClip.nWidth = pSrcSurface->w;
		rSrcClip.nHeight = pSrcSurface->h;
	}

	if(pb == 0)
		pb = pSrcSurface->format->BitsPerPixel;

	if(bAlpha < GAF_ALPHA_DEFAULT
// 		|| !(rSrcClip.nX == 0 && rSrcClip.nY == 0 &&
// 		rSrcClip.nWidth == pSrcSurface->w && rSrcClip.nHeight == pSrcSurface->h)
		)
	{
		if(pb == SDL_PIXELBIT_32)
			return BlendSurface(m_pMainSurface, pSrcSurface, nX, nY, m_rMainArea, rSrcClip, bAlpha);
		else
			return AlphaSurface(m_pMainSurface, pSrcSurface, nX, nY, m_rMainArea, rSrcClip, bAlpha);
	}
	else
	{
		return DrawSurface(m_pMainSurface, pSrcSurface, nX, nY, m_rMainArea, rSrcClip);
	}
}

bool SDL_CCanvas::DrawSurface(SDL_Surface* pDisSurface, SDL_Surface* pSrcSurface,
				    int nX, int nY, GAF_SRect rDisArea, GAF_SRect rSrcClip)
{
	SDL_Rect _rDis;
	_rDis.x = nX;
	_rDis.y = nY;
	SDL_Rect _rScr;
	_rScr.x = rSrcClip.nX;
	_rScr.y = rSrcClip.nY;
	_rScr.w = rSrcClip.nWidth;
	_rScr.h = rSrcClip.nHeight;

	SDL_BlitSurface(pSrcSurface, &_rScr, pDisSurface, &_rDis);

	return true;
}

bool SDL_CCanvas::AlphaSurface(SDL_Surface* pDisSurface, SDL_Surface* pSrcSurface,
	int nX, int nY, GAF_SRect rDisArea, GAF_SRect rSrcClip, BYTE bAlpha)
{
	SDL_gfxSetAlpha(pSrcSurface, bAlpha);

	return DrawSurface(pDisSurface, pSrcSurface, nX, nY, rDisArea, rSrcClip);
}

bool SDL_CCanvas::BlendSurface(SDL_Surface* pDisSurface, SDL_Surface* pSrcSurface,
	int nX, int nY, GAF_SRect rDisArea, GAF_SRect rSrcClip, BYTE bAlpha)
{
	static GAF_SRect s_rDis, s_rSrc;
	static GAF_SPoint s_atDis, s_atSrc;
	static Uint32 s_nDis, s_nSrc;

	if(rDisArea == GAF_RECT_NULL)
	{
		rDisArea.nX = 0;
		rDisArea.nY = 0;
		rDisArea.nWidth = pDisSurface->w;
		rDisArea.nHeight = pDisSurface->h;
	}

	if(rSrcClip == GAF_RECT_NULL)
	{
		rSrcClip.nX = 0;
		rSrcClip.nY = 0;
		rSrcClip.nWidth = pSrcSurface->w;
		rSrcClip.nHeight = pSrcSurface->h;
	}

	// 调整原图绘制区域
	if(rSrcClip.Top() < 0)
	{
		nY += 0 - rSrcClip.nY;
		rSrcClip.Top(0);
	}
	if(rSrcClip.Button() > pSrcSurface->h)
	{
		rSrcClip.Button(pSrcSurface->h);
	}
	if(rSrcClip.Left() < 0)
	{
		nX += 0 - rSrcClip.nX;
		rSrcClip.Left(0);
	}
	if(rSrcClip.Right() > pSrcSurface->w)
	{
		rSrcClip.Right(pSrcSurface->w);
	}

	// 设置原图所在目标图的绘图区域
	s_rSrc.Set(nX, nY, rSrcClip.nWidth, rSrcClip.nHeight);

	// 计算相交区域
	if(rDisArea.Contains(s_rSrc))
	{
		s_rDis = s_rSrc;
	}
	else
	{
		s_rDis = rDisArea.Cut(s_rSrc);
	}

	if(s_rDis.nX < 0 || s_rDis.nY < 0 || s_rDis.nWidth == 0 || s_rDis.nHeight == 0)
		return false;

	// 设置原图绘制区域
	s_rSrc.Set(rSrcClip.nX + (s_rDis.nX - nX),
		rSrcClip.nY + (s_rDis.nY - nY),
		s_rDis.nWidth,
		s_rDis.nHeight);

	if(s_rSrc.nX < 0 || s_rSrc.nY < 0 || s_rSrc.nWidth == 0 || s_rSrc.nHeight == 0)
		return false;

	// 混合
	SDL_LockSurface(pDisSurface);

	s_atDis.Set(s_rDis.nX, s_rDis.nY);
	s_atSrc.Set(s_rSrc.nX, s_rSrc.nY);
	for(; s_atSrc.nY < (int)s_rSrc.Button(); s_atSrc.nY++)
	{
		for(; s_atSrc.nX < (int)s_rSrc.Right(); s_atSrc.nX++)
		{
			s_nDis = GetPixel(pDisSurface, s_atDis.nX, s_atDis.nY);
			s_nSrc = GetPixel(pSrcSurface, s_atSrc.nX, s_atSrc.nY);
			s_nDis = AlphaPixel(s_nDis, s_nSrc, (SDL_DPixelBit)(pSrcSurface->format->BytesPerPixel << 3), bAlpha);
			SetPixel(pDisSurface, s_atDis.nX, s_atDis.nY, s_nDis);

			s_atDis.nX++;
		}
		s_atSrc.nX = s_rSrc.nX;

		s_atDis.nX = s_rDis.nX;
		s_atDis.nY++;
	}

	SDL_UnlockSurface(pDisSurface);

	return true;
}

Uint32 SDL_CCanvas::AlphaPixel(Uint32 nDisColor, Uint32 nSrcColor, SDL_DPixelBit pbSrc, BYTE bAlpha)
{
	enum ColorArray{B, G, R, A};

	static Uint32 s_nRtnColor;
	static BYTE *s_pbDisColor, *s_pbSrcColor, *s_pbRtnColor;

	if(bAlpha == 255)
	{
		return nSrcColor;
	}

	s_nRtnColor = 0;
	s_pbDisColor = (BYTE*)&nDisColor;
	s_pbSrcColor = (BYTE*)&nSrcColor;
	s_pbRtnColor = (BYTE*)&s_nRtnColor;

	if(pbSrc == SDL_PIXELBIT_32 && s_pbSrcColor[A] != 255)
		bAlpha = (bAlpha * s_pbSrcColor[A]) >> 8;

	s_pbRtnColor[B] = (s_pbSrcColor[B] * bAlpha + s_pbDisColor[B] * (255 - bAlpha)) / 255;
	s_pbRtnColor[G] = (s_pbSrcColor[G] * bAlpha + s_pbDisColor[G] * (255 - bAlpha)) / 255;
	s_pbRtnColor[R] = (s_pbSrcColor[R] * bAlpha + s_pbDisColor[R] * (255 - bAlpha)) / 255;
	s_pbRtnColor[A] = (s_pbSrcColor[A] * bAlpha + s_pbDisColor[A] * (255 - bAlpha)) / 255;

	return s_nRtnColor;
}

Uint32 SDL_CCanvas::GetPixel(SDL_Surface* pDisSurface, int nX, int nY)
{
	static UNUM32 s_nDis;

	_MEMCPY(&s_nDis,
		((BYTE*)pDisSurface->pixels) + (pDisSurface->w * nY + nX) * pDisSurface->format->BytesPerPixel,
		sizeof(BYTE) * pDisSurface->format->BytesPerPixel);

	return s_nDis;
}

void SDL_CCanvas::SetPixel(SDL_Surface* pDisSurface, int nX, int nY, Uint32 nColor)
{
	_MEMCPY(((BYTE*)pDisSurface->pixels) + (pDisSurface->w * nY + nX) * pDisSurface->format->BytesPerPixel,
		(&nColor), sizeof(BYTE) * pDisSurface->format->BytesPerPixel);
}

void SDL_CCanvas::ClearScreen()
{
	if(SDL_LockSurface(m_pMainSurface) == 0)
	{
		Uint8* _pPixels;
		_pPixels = (Uint8*)m_pMainSurface->pixels;
		for(int _i = 0; _i < m_pMainSurface->h; _i++)
		{
			memset(_pPixels, 0, m_pMainSurface->w * m_pMainSurface->format->BytesPerPixel);
			_pPixels += m_pMainSurface->pitch;
		}
		SDL_UnlockSurface(m_pMainSurface);
	}
}

SDL_Surface* SDL_CCanvas::SurfaceFormat(SDL_Surface* pSurface)
{
	GAF_CHECK_R(pSurface != NULL, NULL);

	SDL_Surface* _pSurface = SDL_DisplayFormatAlpha(pSurface);
	SDL_FREE_SURFACE(pSurface);
	return _pSurface;
}

SDL_Surface* SDL_CCanvas::CreateText(TTF_Font* pTTF, _STRING strText, GAF_SColour cFront,
	GAF_SColour cBack, int nFontStyle)
{
	SDL_Color _Colour = {cFront.nRed, cFront.nGreen, cFront.nBlue, 0};
	SDL_Surface* _pTextImage = TTF_RenderText_Solid(pTTF, strText.c_str(), _Colour);

	_pTextImage = SurfaceFormat(_pTextImage);

	if(_pTextImage == NULL)
		GAF_ERRMARK();

	return _pTextImage;
}

SDL_Surface* SDL_CCanvas::CreateStyleText(TTF_Font* pTTF, _STRING strText, GAF_SLableStyle* pStyle,
	GAF_SColour cBack, int nFontStyle)
{
	SDL_Surface* _pTextImage = NULL;
	SDL_Surface* _pLayerImage = NULL;
	int _nLayer = 0;
	bool _isOver = false;

	do
	{
		_nLayer++;
		_isOver = true;
		for(int _nX = 0; _nX < pStyle->nWidth; _nX++)
		{
			for(int _nY = 0; _nY < pStyle->nHeight; _nY++)
			{
				if(pStyle->nLayers[_nX][_nY] == _nLayer)
				{
					_isOver = false;

					_pLayerImage = CreateText(pTTF, strText.c_str(), pStyle->cFronts[_nX][_nY]);
					if(_pLayerImage == NULL)
					{
						GAF_ERRMARK();
						SDL_FREE_SURFACE(_pTextImage);
						return NULL;
					}

					if(_pTextImage == NULL)
					{
						static GAF_SImageInfo s_ii;
						_pTextImage = (SDL_Surface*)(GAF_pTHEPLATFORM->NewImage(
							_pLayerImage->w + pStyle->nWidth, _pLayerImage->h + pStyle->nHeight,
							s_ii));

						_pTextImage = SurfaceFormat(_pTextImage);

						if(_pTextImage == NULL)
						{
							GAF_ERRMARK();
							SDL_FREE_SURFACE(_pLayerImage);
							return NULL;
						}
					}

					BlendSurface(_pTextImage, _pLayerImage, _nX, _nY, GAF_RECT_NULL, GAF_RECT_NULL, pStyle->cFronts[_nX][_nY].nAlpha);

					SDL_FREE_SURFACE(_pLayerImage);
				}
			}
		}
	}while(!_isOver);

	return _pTextImage;
}
